package com.filyar.htyd.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.filyar.htyd.entity.Address;
import com.filyar.htyd.entity.AddressCompareResult;
import com.filyar.htyd.entity.CompareTask;
import com.filyar.htyd.mapper.AddressCompareResultMapper;
import com.filyar.htyd.mapper.AddressMapper;
import com.filyar.htyd.mapper.CompareTaskMapper;
import com.filyar.htyd.service.IAddressCompareResultService;
import com.filyar.htyd.service.IAddressService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author filyar
 * @since 2024-11-01
 * @e-mail root@filyar.com
 */
@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressService {

    @Resource
    private AddressMapper addressMapper;
    @Resource
    private IAddressCompareResultService addressCompareResultService;
    @Resource
    private CompareTaskMapper compareTaskMapper;
    @Resource
    private AddressCompareResultMapper addressCompareResultMapper;
    @Resource
    private CompareResultServiceImpl compareResultServiceImpl;

    @Async("async-executor")
    @Override
    public void CompareWholeTable() {
        addressCompareResultMapper.truncateTable();
        List<Address> addresses = addressMapper.selectList(null);
        ArrayList<AddressCompareResult> addressCompareResults = new ArrayList<>();
        DateTime executionStartTime = DateTime.now();
        String serialNumber = DateUtil.now() + "---" + IdUtil.fastSimpleUUID();

        CompareTask compareTask = new CompareTask();
        compareTask.setExecutionCreateTime(executionStartTime);
        compareTask.setSerialNumber(serialNumber);
        compareTask.setExecutionStatus(0);
//        compareTask.setOperatorName((JSONObject.parseObject(JSONObject.toJSONString(StpUtil.getSession().get("user")), User.class)).getNickname());
        compareTask.setExecutionProgress(0);
        compareTaskMapper.insert(compareTask);
        int azSize = addresses.size();
        int chunkSize = azSize / 100;
        int size = addresses.size();
        for (int i = 0; i < size; i++) {
            if (i % chunkSize == 0) {
                DateTime loopTime = DateTime.now();
                compareTask.setExecutionProgress(i / chunkSize);
                compareTask.setExecutionTime(DateUtil.between(executionStartTime,loopTime, DateUnit.SECOND));
                compareTaskMapper.updateById(compareTask);
            }
            Address address = addresses.get(i);
            String addressAddress = address.getAddress();
            HashSet<String> currentBigLoopAddressHashSet = new HashSet<>(Arrays.asList(address.getAddress().split("")));
            for (int j = i + 1; j < size; j++) {
                AddressCompareResult compareResult = getCompareResult(currentBigLoopAddressHashSet, addressAddress, addresses.get(j).getAddress());
                if (compareResult != null){
                    addressCompareResults.add(compareResult);
                }
            }
        }
        DateTime executionEndTime = DateTime.now();
        compareTask.setExecutionProgress(100);
        compareTask.setExecutionEndTime(executionEndTime);
        compareTask.setSaveStartTime(executionEndTime);
        compareTask.setExecutionTime(DateUtil.between(executionStartTime,executionEndTime, DateUnit.SECOND));
        compareTask.setExecutionStatus(1);
        compareTaskMapper.updateById(compareTask);

        //将结果保存到数据库
        int batchSize = addressCompareResults.size() / 100;
        ArrayList<List<AddressCompareResult>> batches = new ArrayList<>();
        for(int i = 0;i< addressCompareResults.size();i+=batchSize){
            batches.add(addressCompareResults.subList(i,Math.min(addressCompareResults.size(),i+batchSize)));
        }

        int core = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(core);
        AtomicInteger completedTasks = new AtomicInteger(0);
        try {
            compareTask.setSaveStatus(0);
            compareTask.setSaveProgress(0);
            compareTaskMapper.updateById(compareTask);
            for (int i = 0; i < batches.size(); i++) {
                final int batchIndex = i;
                executorService.execute(() -> {
                    addressCompareResultService.saveBatch(batches.get(batchIndex));
                    int completed = completedTasks.incrementAndGet();
                    // 每完成10个任务或最后一个任务时更新进度
                    if (completed % 10 == 0 || batchIndex == batches.size() - 1) {
                        synchronized (compareTask) {
                            compareTask.setSaveProgress(completed);

                            // 更新状态
                            if (batchIndex == batches.size() - 1) {
                                compareTask.setSaveStatus(1); // 设置为完成状态
                                compareTask.setSaveProgress(100); // 更新为100%
                                DateTime saveEndTime = DateTime.now();
                                compareTask.setSavaEndTime(saveEndTime);
                                compareTask.setSaveTime(DateUtil.between(executionEndTime, saveEndTime, DateUnit.SECOND));
                            }
                            compareTaskMapper.updateById(compareTask);
                        }
                    }
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdownNow(); // 超时则强制关闭
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }

    }

    @Override
    public List<AddressCompareResult> check(Address address) {
        List<Address> addresses = addressMapper.selectList(null);
        String inputAddress = address.getAddress();
        HashSet<String> inputHashSetAddress = new HashSet<>(Arrays.asList(inputAddress.split("")));
        ArrayList<AddressCompareResult> addressCompareResults = new ArrayList<>();
        for (Address loopAddress : addresses) {
            String currentLoopStrAddress = loopAddress.getAddress(); // 先获取地址
            AddressCompareResult compareResult = getCompareResult(inputAddress, inputHashSetAddress, currentLoopStrAddress,address.getLikePercent());
            if (compareResult != null) {
                addressCompareResults.add(compareResult);
            }
        }
        return addressCompareResults;
    }


    /**
     * 单个地址对比工具函数
     * @param input
     * @param inputHashSet
     * @param currentLoopAddress
     * @return
     */
    private AddressCompareResult getCompareResult(String input, HashSet inputHashSet, String currentLoopAddress,double percent) {
        String[] compareAddressChars = currentLoopAddress.split("");
        int likeCount = 0;
        for (String compareAddressChar : compareAddressChars) {
            if (inputHashSet.contains(compareAddressChar)) {
                likeCount++;
            }
        }
        int max = Math.max(inputHashSet.size(), compareAddressChars.length);
        double likePercent = 0;
        if (likeCount == 0){
            likePercent = 0;
        }else {
            likePercent = Double.parseDouble(new DecimalFormat("#.##").format(likeCount / (double) max));
        }
        if (likePercent > percent){
            AddressCompareResult addressCompareResult = new AddressCompareResult();
            addressCompareResult.setAddress(input);
            addressCompareResult.setCompareAddress(currentLoopAddress);
            addressCompareResult.setLikeCount(likeCount);
            addressCompareResult.setLikePercent(likePercent);
            return addressCompareResult;
        }
        return null;

    }

    /**
     * 全表对比工具函数
     * @param currentBigLoopAddressHashSet
     * @param address
     * @param compareAddress
     * @return
     */
    private AddressCompareResult getCompareResult(HashSet currentBigLoopAddressHashSet,String address,String compareAddress){
        String[] compareAddressChars = compareAddress.split("");
        int likeCount = 0;
        for (String compareAddressChar : compareAddressChars) {
            if (currentBigLoopAddressHashSet.contains(compareAddressChar)) {
                likeCount++;
            }
        }
        int max = Math.max(currentBigLoopAddressHashSet.size(), compareAddressChars.length);
        double likePercent = 0;
        if (likeCount == 0){
            likePercent = 0;
        }else {
            likePercent = Double.parseDouble(new DecimalFormat("#.##").format(likeCount / (double) max));
        }
        if (likePercent > 0.5){
            AddressCompareResult addressCompareResult = new AddressCompareResult();
            addressCompareResult.setAddress(address);
            addressCompareResult.setCompareAddress(compareAddress);
            addressCompareResult.setLikeCount(likeCount);
            addressCompareResult.setLikePercent(likePercent);
            return addressCompareResult;
        }
        return null;


    }
}
